#include <cUdp.h>
#include <lxFileOpt.h>

enum UDP_CHECK_STATE_ENUM
{
    UDP_CHECK_STATE_IDLE = 0,
    UDP_CHECK_STATE_INIT,
    UDP_CHECK_STATE_RUN,
    UDP_CHECK_STATE_QUIT,
};
int udpServerInit(struct udpCheckStruct *udpdata)
{
    struct sockaddr_in sin;
    int broad = 1;
    if (!udpdata)
    {
        logerrorc("");
        return -1;
    }
    bzero(&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    sin.sin_port = htons(8887);
    if (udpdata->udpSock >= 0)
    {
        close(udpdata->udpSock);
        udpdata->udpSock = -1;
    }
    udpdata->udpSock = socket(AF_INET, SOCK_DGRAM, 0);
    logdebugc("udp sock:%d", udpdata->udpSock);
    if (udpdata->udpSock < 0)
    {
        logdebugc("!!! create udp error");
        return -1;
    }
    setsockopt(udpdata->udpSock, SOL_SOCKET, SO_BROADCAST, &broad, sizeof(broad));
    if (-1 == bind(udpdata->udpSock, (struct sockaddr *)&sin, sizeof(sin)))
    {
        logdebugc("!!! bind socket error");
        return -1;
    }
    return fileCfgNoBlock(udpdata->udpSock);
}
int udpStMcCkIdle(struct statMcBaseStruct *thisState)
{
    struct udpCheckStruct *udpData;
    if (!(thisState && thisState->cstaMgr && thisState->cstaMgr->staCtxt))
    {
        logerrorc("");
        return -1;
    }
    udpData = (struct udpCheckStruct *)thisState->cstaMgr->staCtxt;
    if (sysTmRunMs(udpData->msTimer) < 5000)
    {
        return -1;
    }
    if (udpData->udpSock >= 0)
    {
        close(udpData->udpSock);
        udpData->udpSock = -1;
    }
    logdebugc("%d", udpData->udpSock);
    sysTmBeg(udpData->msTimer);
    statMcMngTranst(thisState->cstaMgr, UDP_CHECK_STATE_INIT);
    return 0;
}
int udpStMcCkInit(struct statMcBaseStruct *thisState)
{
    if (udpServerInit((struct udpCheckStruct *)thisState->cstaMgr->staCtxt) < 0)
    {
        logdebugc("");
        statMcMngTranst(thisState->cstaMgr, UDP_CHECK_STATE_QUIT);
    }
    else
    {
        logdebugc("");
        statMcMngTranst(thisState->cstaMgr, UDP_CHECK_STATE_RUN);
    }
    return 0;
}
int udpStMcCkRun(struct statMcBaseStruct *thisState)
{
    struct udpCheckStruct *udpData = (struct udpCheckStruct *)thisState->cstaMgr->staCtxt;
    int tmpflag = 0;
    if (udpData->udpSock < 0)
    {
        logdebugc("");
        statMcMngTranst(thisState->cstaMgr, UDP_CHECK_STATE_QUIT);
        return -1;
    }
    struct sockaddr_in from;
    char buf[UDP_MAX_DATA_SIZE];
    int get_len;
    int from_len = sizeof(from);
    tmpflag = fileOptSelect(udpData->udpSock, 200);
    if (tmpflag < 0)
    {
        logdebugc("");
        statMcMngTranst(thisState->cstaMgr, UDP_CHECK_STATE_QUIT);
        return -1;
    }
    else if (tmpflag == 0)
    {
        return 0;
    }
    get_len = recvfrom(udpData->udpSock, buf, UDP_MAX_DATA_SIZE, 0, (struct sockaddr *)&from, (socklen_t *)&from_len);
    logdebugc("receive size=%d, data=%s", get_len, buf);
    sendto(udpData->udpSock, buf, get_len, 0, (struct sockaddr *)&from, from_len);
    return 0;
}

int udpStMcCkQuit(struct statMcBaseStruct *thisState)
{
    struct udpCheckStruct *udpData = (struct udpCheckStruct *)thisState->cstaMgr->staCtxt;
    logdebugc("");
    if (udpData->udpSock >= 0)
    {
        close(udpData->udpSock);
        udpData->udpSock = -1;
    }
    statMcMngTranst(thisState->cstaMgr, UDP_CHECK_STATE_IDLE);
    return 0;
}

struct statMcMngStruct udpStCheckMng;
struct udpCheckStruct udpStContext = {-1, 0};

struct statMcBaseStruct myCheckStates[] = {
    statMcBaseDefine(NULL, udpStMcCkIdle, NULL, UDP_CHECK_STATE_IDLE, &udpStCheckMng),
    statMcBaseDefine(NULL, udpStMcCkInit, NULL, UDP_CHECK_STATE_INIT, &udpStCheckMng),
    statMcBaseDefine(NULL, udpStMcCkRun, NULL, UDP_CHECK_STATE_RUN, &udpStCheckMng),
    statMcBaseDefine(NULL, udpStMcCkQuit, NULL, UDP_CHECK_STATE_QUIT, &udpStCheckMng),
};

int main()
{
    statMcMngInit(&udpStCheckMng, &udpStContext, myCheckStates, ARRAY_LEN(myCheckStates), UDP_CHECK_STATE_IDLE);
    while (1)
    {
        statMcMngRun(&udpStCheckMng);
        usleep(20000);
    }
    statMcMngQuit(&udpStCheckMng);
}
